#pragma once
#include "IO.h"
#include <cassert>
#include <cstdlib>
#include <vector>
#include <cstring>
#include <tuple>
#include <cmath>
using namespace std;

#define STATISITIC_ON

#define MAX_DISK_NUM (10 + 1)
#define MAX_DISK_SIZE (16384 + 1)
#define MAX_REQUEST_NUM (30000000 + 1)
#define MAX_OBJECT_NUM (100000 + 1)
#define MAX_TAG_NUM (16+1)
#define REP_NUM (3)
#define FRE_PER_SLICING (1800)
#define EXTRA_TIME (105)
#define MAX_TIME_SLICING (86400 + EXTRA_TIME + 1)
#define MAX_OBJECT_SIZE (5+1)
#define MAX_G (500+1)
#define MAX_T (86400+1)

struct Request {
    int object_id,burntime;
    int prev_id,remain;
    bool is_done[MAX_OBJECT_SIZE],isbusy;
	bool is_completed() {return remain==0;}
};

struct Object {
    int replica[REP_NUM + 1];
    int* unit[REP_NUM + 1];
    int size;
    int last_request_point;
    int tag;
    bool is_delete;
    vector<int>requests;
    int it;
    Object(){it=0;}
};

extern int timestamp;
extern int T, M, N, V, G, K1, K2;
extern int Round;

extern Request request[MAX_REQUEST_NUM];
extern Object object[MAX_OBJECT_NUM];
extern int dis_canread[MAX_G];

//Disks statement
struct DiskPoint {
	int pos,pretoken;
	inline int dis_tox(int x)const {return (x+V-pos)%V;}
};
extern int disk[MAX_DISK_NUM][MAX_DISK_SIZE],unit_num[MAX_DISK_NUM][MAX_DISK_SIZE];
extern DiskPoint disk_point[MAX_DISK_NUM][2];

// Interaction record in round 1
extern int n_deletes[MAX_TIME_SLICING];
extern int n_writes[MAX_TIME_SLICING];
extern int n_reads[MAX_TIME_SLICING];
extern vector<int> delete_datas[MAX_TIME_SLICING];
extern vector<tuple<int, int, int>> write_datas[MAX_TIME_SLICING];
extern vector<tuple<int, int>> read_datas[MAX_TIME_SLICING];

// data in round 1
extern int num_read[MAX_TAG_NUM][MAX_TIME_SLICING];
extern int num_write[MAX_TAG_NUM][MAX_TIME_SLICING];
extern int num_delete[MAX_TAG_NUM][MAX_TIME_SLICING];
extern double num_read_for_gather[MAX_TAG_NUM][MAX_TIME_SLICING];
extern int sum[MAX_TAG_NUM][MAX_TIME_SLICING*2];

//Sort
extern int vtag[MAX_TAG_NUM],tagpos[MAX_TAG_NUM];
void Sort();

//Actions
void timestamp_action();
void delete_action(int round, int time);
void write_action(int round, int time);
void write_action2();
void read_action(int round, int time);
void gbCollect(int round);
void gbCollect2();
void incre_action();
void gather_action();

//Basic Function
inline void inc(int &x){x=(x==V?1:x+1);}
inline void dec(int &x){x=(x==1?V:x-1);}
inline int point_away(int x,int d){int ans=(x+d+V);while(ans>V) ans-=V;return ans;}
inline int dis_between(int x,int y){return y>=x?y-x:y-x+V;}
inline int get_num_read(int tag,int l,int r=0){
    if(!r)
        r=l;
    if(r>T+EXTRA_TIME)
        r=T+EXTRA_TIME;
    return num_read[tag][r]-num_read[tag][l-1];
}
inline int get_num_write(int tag,int l,int r=0){
    if(!r)
        r=l;
    if(r>T+EXTRA_TIME)
        r=T+EXTRA_TIME;
    return num_write[tag][r]-num_write[tag][l-1];
}
inline int get_num_delete(int tag,int l,int r=0){
    if(!r)
        r=l;
    if(r>T+EXTRA_TIME)
        r=T+EXTRA_TIME;
    return num_delete[tag][r]-num_delete[tag][l-1];
}
void get_start_end(int &st,int &ed,int tag);